#include "Texture.h"
#include "DXDevice.h"
#include <algorithm>
using namespace std;
Texture* TextureManager::LoadTexture(const char* name)
{
	for(unsigned int i = 0;i<textureList.size();i++)
	{
		if(strcmp(textureList[i]->name, name) == 0)
		{
			return textureList[i];
		}
	}
	Texture* texture = new Texture();
	char* path = NULL;
	SafeMergeCHAR(&path, directory, name);
	wchar_t* wfileName = new wchar_t[strlen(path)+1];
	ConvertCharToWchar(wfileName, path);
	SafeDeleteArray(path);
	HRESULT rs = DirectX::CreateDDSTextureFromFile(DXDevice::GetInstance()->GetD3D11Device(), wfileName, &(texture->resource), &(texture->shaderResourceView));
	SafeDeleteArray(wfileName);
	if(S_OK == rs)
	{
		texture->name = new char[strlen(name)+1];
		strcpy(texture->name, name);
		GetTextureSize(texture->resource, &(texture->width), &(texture->height));
		textureList.push_back(texture);
		return texture;
	}
	else
	{
		SafeDelete(texture);
		return NULL;
	}
}
Texture* TextureManager::GetTexture(const char* name)
{
	for(unsigned int i = 0;i<textureList.size();i++)
	{
		if(strcmp(textureList[i]->name, name) == 0)
		{
			return textureList[i];
		}
	}
	return NULL;

}
Texture* TextureManager::CreateTexture(const char* name, int width, int height, DXGI_FORMAT format,  UINT bindFlags, int aa)
{
	for(unsigned int i = 0;i<textureList.size();i++)
	{
		if(strcmp(textureList[i]->name, name) == 0)
		{
			return textureList[i];
		}
	}
	D3D11_TEXTURE2D_DESC textureDesc;
	D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;

	// Initialize the render target texture description.
	ZeroMemory(&textureDesc, sizeof(textureDesc));

	// Setup the render target texture description.
	textureDesc.Width = width;
	textureDesc.Height = height;
	textureDesc.MipLevels = 1;
	textureDesc.ArraySize = 1;
	textureDesc.Format = format;
	if(aa == 0)
	{
		textureDesc.SampleDesc.Count = 1;
	}
	textureDesc.Usage = D3D11_USAGE_DEFAULT;
	textureDesc.BindFlags = bindFlags | D3D11_BIND_SHADER_RESOURCE;
	textureDesc.CPUAccessFlags = 0;
	textureDesc.MiscFlags = 0;
	Texture* texture = new Texture();
	ID3D11Texture2D* d3d11Texture2D = 0;
	HRESULT result = DXDevice::GetInstance()->GetD3D11Device()->CreateTexture2D(&textureDesc, NULL, &d3d11Texture2D);
	if(FAILED(result))
	{
		return NULL;
	}
	texture->resource = d3d11Texture2D;
	D3D11_SHADER_RESOURCE_VIEW_DESC shaderResourceViewDesc;
	ZeroMemory(&shaderResourceViewDesc, sizeof(shaderResourceViewDesc));
	if(format == DXGI_FORMAT_R24G8_TYPELESS)
	{
		shaderResourceViewDesc.Format = DXGI_FORMAT_R24_UNORM_X8_TYPELESS;
	}
	else
	{
		shaderResourceViewDesc.Format = textureDesc.Format;
	}
	shaderResourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
	shaderResourceViewDesc.Texture2D.MostDetailedMip = 0;
	shaderResourceViewDesc.Texture2D.MipLevels = 1;

	// Create the shader resource view.
	result = DXDevice::GetInstance()->GetD3D11Device()->CreateShaderResourceView(texture->resource, &shaderResourceViewDesc, &texture->shaderResourceView);
	if(FAILED(result))
	{
		return NULL;
	}
	return texture;
}
void TextureManager::ReleaseTexure(Texture* texture)
{
	textureList.erase(std::remove(textureList.begin(), textureList.end(), texture), textureList.end());
	SafeDelete(texture);
}
void TextureManager::ReleaseTexure(const char* name)
{
	for(std::vector<Texture*>::iterator it = textureList.begin(); it != textureList.end(); ++it)
	{
		if(strcmp((*it)->name, name) == 0)
		{
			SafeDelete(*it);
			textureList.erase(it);
			break;
		}
	}
}
void GetTextureSize( ID3D11Resource* res, UINT* width, UINT* height )
{
    assert( res != 0 );

    // This is the most generic solution. you can make it a lot
    // simpler if you know it will always be a 2D texture file
    D3D11_RESOURCE_DIMENSION dim;
    res->GetType( &dim );
    switch(dim)
    {
        case D3D11_RESOURCE_DIMENSION_TEXTURE1D:
            { 
                 auto txt = reinterpret_cast<ID3D11Texture1D*>( res );
                 D3D11_TEXTURE1D_DESC desc;
                 txt->GetDesc( &desc );
                 if ( width ) *width = desc.Width;
                 if ( height ) *height = 1;
            }
            break;
        case D3D11_RESOURCE_DIMENSION_TEXTURE2D:
            {
                 auto txt = reinterpret_cast<ID3D11Texture2D*>( res );
                 D3D11_TEXTURE2D_DESC desc;
                 txt->GetDesc( &desc );
                 if ( width ) *width = desc.Width;
                 if ( height ) *height = desc.Height;
            }
            break;
        case D3D11_RESOURCE_DIMENSION_TEXTURE3D:
            {
                 auto txt = reinterpret_cast<ID3D11Texture3D*>( res );
                 D3D11_TEXTURE3D_DESC desc;
                 txt->GetDesc( &desc );
                 if ( width ) *width = desc.Width;
                 if ( height ) *height = desc.Height;
            }
            break;
        default:
             if ( width ) *width = 0;
             if ( height ) *height = 0;
            break;
    }
}